home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / sc_22.zip / CC4.C < prev    next >
C/C++ Source or Header  |  1988-08-06  |  24KB  |  765 lines

  1. /*
  2. ** Small-C Compiler -- Part 4 -- Back End.
  3. ** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix
  4. ** All rights reserved.
  5. */
  6. #include <stdio.h>
  7. #include "cc.h"
  8.  
  9. /* #define DISOPT */       /* display optimizations values */
  10.  
  11. /*************************** externals ****************************/
  12.  
  13. extern char
  14.   *cptr, *macn, *litq, *symtab, optimize, ssname[NAMESIZE];
  15.  
  16. extern int
  17.   *stage, litlab, litptr, csp, output, oldseg, usexpr,
  18.   *snext, *stail, *slast;
  19.  
  20.  
  21. /***************** optimizer command definitions ******************/
  22.  
  23.              /*     --      p-codes must not overlap these */
  24. #define any     0x00FF   /* matches any p-code */
  25. #define _pop    0x00FE   /* matches if corresponding POP2 exists */
  26. #define pfree   0x00FD   /* matches if pri register free */
  27. #define sfree   0x00FC   /* matches if sec register free */
  28. #define comm    0x00FB   /* matches if registers are commutative */
  29.  
  30.              /*     --      these digits are reserved for n */
  31. #define go      0x0100   /* go n entries */
  32. #define gc      0x0200   /* get code from n entries away */
  33. #define gv      0x0300   /* get value from n entries away */
  34. #define sum     0x0400   /* add value from nth entry away */
  35. #define neg     0x0500   /* negate the value */
  36. #define ife     0x0600   /* if value == n do commands to next 0 */
  37. #define ifl     0x0700   /* if value <  n do commands to next 0 */
  38. #define swv     0x0800   /* swap value with value n entries away */
  39. #define topop   0x0900   /* moves |code and current value to POP2 */
  40.  
  41. #define p1      0x0001   /* plus 1 */
  42. #define p2      0x0002   /* plus 2 */
  43. #define p3      0x0003   /* plus 3 */
  44. #define p4      0x0004   /* plus 4 */
  45. #define m1      0x00FF   /* minus 1 */
  46. #define m2      0x00FE   /* minus 2 */
  47. #define m3      0x00FD   /* minus 3 */
  48. #define m4      0x00FC   /* minus 4 */
  49.  
  50. #define PRI      0030    /* primary register bits */
  51. #define SEC      0003    /* secondary register bits */
  52. #define USES     0011    /* use register contents */
  53. #define ZAPS     0022    /* zap register contents */
  54. #define PUSHES   0100    /* pushes onto the stack */
  55. #define COMMUTES 0200    /* commutative p-code */
  56.  
  57. /******************** optimizer command lists *********************/
  58.  
  59. int
  60.   seq00[] = {0,ADD12,MOVE21,0,                       /* ADD21 */
  61.              go|p1,ADD21,0},
  62.  
  63.   seq01[] = {0,ADD1n,0,                              /* rINC1 or rDEC1 ? */ 
  64.              ifl|m2,0,ifl|0,rDEC1,neg,0,ifl|p3,rINC1,0,0},
  65.  
  66.   seq02[] = {0,ADD2n,0,                              /* rINC2 or rDEC2 ? */ 
  67.              ifl|m2,0,ifl|0,rDEC2,neg,0,ifl|p3,rINC2,0,0},
  68.  
  69.   seq03[] = {0,rDEC1,PUTbp1,rINC1,0,                 /* SUBbpn or DECbp */
  70.              go|p2,ife|p1,DECbp,0,SUBbpn,0},
  71.  
  72.   seq04[] = {0,rDEC1,PUTwp1,rINC1,0,                 /* SUBwpn or DECwp */
  73.              go|p2,ife|p1,DECwp,0,SUBwpn,0},
  74.  
  75.   seq05[] = {0,rDEC1,PUTbm1,rINC1,0,                 /* SUB_m_ COMMAn */
  76.              go|p1,SUB_m_,go|p1,COMMAn,go|m1,0},
  77.  
  78.   seq06[] = {0,rDEC1,PUTwm1,rINC1,0,                 /* SUB_m_ COMMAn */
  79.              go|p1,SUB_m_,go|p1,COMMAn,go|m1,0},
  80.  
  81.   seq07[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1p,0,  /* GETw2m GETb1p */
  82.              go|p4,gv|m3,go|m1,GETw2m,gv|m3,0},
  83.  
  84.   seq08[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1pu,0, /* GETw2m GETb1pu */
  85.              go|p4,gv|m3,go|m1,GETw2m,gv|m3,0},
  86.  
  87.   seq09[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETw1p,0,  /* GETw2m GETw1p */
  88.              go|p4,gv|m3,go|m1,GETw2m,gv|m3,0},
  89.  
  90.   seq10[] = {0,GETw1m,GETw2m,SWAP12,0,               /* GETw2m GETw1m */
  91.              go|p2,GETw1m,gv|m1,go|m1,gv|m1,0},
  92.  
  93.   seq11[] = {0,GETw1m,MOVE21,0,                      /* GETw2m */
  94.              go|p1,GETw2m,gv|m1,0},
  95.  
  96.   seq12[] = {0,GETw1m,PUSH1,pfree,0,                 /* PUSHm */
  97.              go|p1,PUSHm,gv|m1,0},
  98.  
  99.   seq13[] = {0,GETw1n,PUTbm1,pfree,0,                /* PUT_m_ COMMAn */
  100.              PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0},
  101.  
  102.   seq14[] = {0,GETw1n,PUTwm1,pfree,0,                /* PUT_m_ COMMAn */ 
  103.              PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0}, 
  104.  
  105.   seq15[] = {0,GETw1p,PUSH1,pfree,0,                 /* PUSHp */ 
  106.              go|p1,PUSHp,gv|m1,0},
  107.  
  108.   seq16[] = {0,GETw1s,GETw2n,ADD12,MOVE21,0,         /* GETw2s ADD2n */
  109.              go|p3,ADD2n,gv|m2,go|m1,GETw2s,gv|m2,0},
  110.  
  111.   seq17[] = {0,GETw1s,GETw2s,SWAP12,0,               /* GETw2s GETw1s */
  112.              go|p2,GETw1s,gv|m1,go|m1,GETw2s,gv|m1,0},
  113.  
  114.   seq18[] = {0,GETw1s,MOVE21,0,                      /* GETw2s */
  115.              go|p1,GETw2s,gv|m1,0},
  116.  
  117.   seq19[] = {0,GETw2m,GETw1n,SWAP12,SUB12,0,         /* GETw1m SUB1n */
  118.              go|p3,SUB1n,gv|m2,go|m1,GETw1m,gv|m2,0},
  119.  
  120.   seq20[] = {0,GETw2n,ADD12,0,                       /* ADD1n */ 
  121.              go|p1,ADD1n,gv|m1,0},
  122.  
  123.   seq21[] = {0,GETw2s,GETw1n,SWAP12,SUB12,0,         /* GETw1s SUB1n */ 
  124.              go|p3,SUB1n,gv|m2,go|m1,GETw1s,gv|m2,0},
  125.  
  126.   seq22[] = {0,rINC1,PUTbm1,rDEC1,0,                 /* ADDm_ COMMAn */ 
  127.              go|p1,ADDm_,go|p1,COMMAn,go|m1,0}, 
  128.  
  129.   seq23[] = {0,rINC1,PUTwm1,rDEC1,0,                 /* ADDm_ COMMAn */ 
  130.              go|p1,ADDm_,go|p1,COMMAn,go|m1,0}, 
  131.  
  132.   seq24[] = {0,rINC1,PUTbp1,rDEC1,0,                 /* ADDbpn or INCbp */ 
  133.              go|p2,ife|p1,INCbp,0,ADDbpn,0}, 
  134.  
  135.   seq25[] = {0,rINC1,PUTwp1,rDEC1,0,                 /* ADDwpn or INCwp */ 
  136.              go|p2,ife|p1,INCwp,0,ADDwpn,0}, 
  137.  
  138.   seq26[] = {0,MOVE21,GETw1n,SWAP12,SUB12,0,         /* SUB1n */
  139.              go|p3,SUB1n,gv|m2,0},
  140.  
  141.   seq27[] = {0,MOVE21,GETw1n,comm,0,                 /* GETw2n comm */
  142.              go|p1,GETw2n,0},
  143.  
  144.   seq28[] = {0,POINT1m,GETw2n,ADD12,MOVE21,0,        /* POINT2m_ PLUSn */
  145.              go|p3,PLUSn,gv|m2,go|m1,POINT2m_,gv|m2,0},
  146.  
  147.   seq29[] = {0,POINT1m,MOVE21,pfree,0,               /* POINT2m */
  148.              go|p1,POINT2m,gv|m1,0},
  149.  
  150.   seq30[] = {0,POINT1m,PUSH1,pfree,_pop,0,           /* ... POINT2m */
  151.              topop|POINT2m,go|p2,0},
  152.  
  153.   seq31[] = {0,POINT1s,GETw2n,ADD12,MOVE21,0,        /* POINT2s */
  154.              sum|p1,go|p3,POINT2s,gv|m3,0},
  155.  
  156.   seq32[] = {0,POINT1s,PUSH1,MOVE21,0,               /* POINT2s PUSH2 */
  157.              go|p1,POINT2s,gv|m1,go|p1,PUSH2,go|m1,0},
  158.  
  159.   seq33[] = {0,POINT1s,PUSH1,pfree,_pop,0,           /* ... POINT2s */
  160.              topop|POINT2s,go|p2,0},
  161.  
  162.   seq34[] = {0,POINT1s,MOVE21,0,                     /* POINT2s */
  163.              go|p1,POINT2s,gv|m1,0},
  164.  
  165.   seq35[] = {0,POINT2m,GETb1p,sfree,0,               /* GETb1m */
  166.              go|p1,GETb1m,gv|m1,0},
  167.  
  168.   seq36[] = {0,POINT2m,GETb1pu,sfree,0,              /* GETb1mu */
  169.              go|p1,GETb1mu,gv|m1,0},
  170.  
  171.   seq37[] = {0,POINT2m,GETw1p,sfree,0,               /* GETw1m */
  172.              go|p1,GETw1m,gv|m1,0},
  173.  
  174.   seq38[] = {0,POINT2m_,PLUSn,GETw1p,sfree,0,        /* GETw1m_ PLUSn */
  175.              go|p2,gc|m1,gv|m1,go|m1,GETw1m_,gv|m1,0},
  176.  
  177.   seq39[] = {0,POINT2s,GETb1p,sfree,0,               /* GETb1s */
  178.              sum|p1,go|p1,GETb1s,gv|m1,0},
  179.  
  180.   seq40[] = {0,POINT2s,GETb1pu,sfree,0,              /* GETb1su */
  181.              sum|p1,go|p1,GETb1su,gv|m1,0},
  182.  
  183.   seq41[] = {0,POINT2s,GETw1p,PUSH1,pfree,0,         /* PUSHs */
  184.              sum|p1,go|p2,PUSHs,gv|m2,0},
  185.  
  186.   seq42[] = {0,POINT2s,GETw1p,sfree,0,               /* GETw1s */
  187.              sum|p1,go|p1,GETw1s,gv|m1,0},
  188.  
  189.   seq43[] = {0,PUSH1,any,POP2,0,                     /* MOVE21 any */
  190.              go|p2,gc|m1,gv|m1,go|m1,MOVE21,0},
  191.  
  192.   seq44[] = {0,PUSHm,_pop,0,                         /* ... GETw2m */
  193.              topop|GETw2m,go|p1,0},
  194.  
  195.   seq45[] = {0,PUSHp,any,POP2,0,                     /* GETw2p ... */
  196.              go|p2,gc|m1,gv|m1,go|m1,GETw2p,gv|m1,0},
  197.  
  198.   seq46[] = {0,PUSHs,_pop,0,                         /* ... GETw2s */
  199.              topop|GETw2s,go|p1,0},
  200.  
  201.   seq47[] = {0,SUB1n,0,                              /* rDEC1 or rINC1 ? */
  202.              ifl|m2,0,ifl|0,rINC1,neg,0,ifl|p3,rDEC1,0,0};
  203.  
  204. #define HIGH_SEQ  47
  205. int seq[HIGH_SEQ + 1];  
  206. setseq() {
  207.   seq[ 0] = seq00;  seq[ 1] = seq01;  seq[ 2] = seq02;  seq[ 3] = seq03;
  208.   seq[ 4] = seq04;  seq[ 5] = seq05;  seq[ 6] = seq06;  seq[ 7] = seq07;
  209.   seq[ 8] = seq08;  seq[ 9] = seq09;  seq[10] = seq10;  seq[11] = seq11;
  210.   seq[12] = seq12;  seq[13] = seq13;  seq[14] = seq14;  seq[15] = seq15;
  211.   seq[16] = seq16;  seq[17] = seq17;  seq[18] = seq18;  seq[19] = seq19;
  212.   seq[20] = seq20;  seq[21] = seq21;  seq[22] = seq22;  seq[23] = seq23;
  213.   seq[24] = seq24;  seq[25] = seq25;  seq[26] = seq26;  seq[27] = seq27;
  214.   seq[28] = seq28;  seq[29] = seq29;  seq[30] = seq30;  seq[31] = seq31;
  215.   seq[32] = seq32;  seq[33] = seq33;  seq[34] = seq34;  seq[35] = seq35;
  216.   seq[36] = seq36;  seq[37] = seq37;  seq[38] = seq38;  seq[39] = seq39;
  217.   seq[40] = seq40;  seq[41] = seq41;  seq[42] = seq42;  seq[43] = seq43;
  218.   seq[44] = seq44;  seq[45] = seq45;  seq[46] = seq46;  seq[47] = seq47;
  219.   } 
  220.  
  221. /***************** assembly-code strings ******************/
  222.  
  223. int code[PCODES];
  224.  
  225. /*
  226. ** First byte contains flag bits indicating:
  227. **    the value in ax is needed (010) or zapped (020)
  228. **    the value in bx is needed (001) or zapped (002)
  229. */
  230. setcodes() {
  231.   setseq();
  232.   code[ADD12]   = "\211ADD AX,BX\n";
  233.   code[ADD1n]   = "\010?ADD AX,<n>\n??";
  234.   code[ADD21]   = "\211ADD BX,AX\n";
  235.   code[ADD2n]   = "\010?ADD BX,<n>\n??";
  236.   code[ADDbpn]  = "\001ADD BYTE PTR [BX],<n>\n";
  237.   code[ADDwpn]  = "\001ADD WORD PTR [BX],<n>\n";
  238.   code[ADDm_]   = "\000ADD <m>";
  239.   code[ADDSP]   = "\000?ADD SP,<n>\n??";
  240.   code[AND12]   = "\211AND AX,BX\n";
  241.   code[ANEG1]   = "\010NEG AX\n";
  242.   code[ARGCNTn] = "\000?MOV CL,<n>?XOR CL,CL?\n";
  243.   code[ASL12]   = "\011MOV CX,AX\nMOV AX,BX\nSAL AX,CL\n";
  244.   code[ASR12]   = "\011MOV CX,AX\nMOV AX,BX\nSAR AX,CL\n";
  245.   code[CALL1]   = "\010CALL AX\n";
  246.   code[CALLm]   = "\020CALL <m>\n";
  247.   code[BYTE_]   = "\000 DB ";
  248.   code[BYTEn]   = "\000 DB <n>\n";
  249.   code[BYTEr0]  = "\000 DB <n> DUP(0)\n";
  250.   code[COM1]    = "\010NOT AX\n";
  251.   code[COMMAn]  = "\000,<n>\n";
  252.   code[DBL1]    = "\010SHL AX,1\n";
  253.   code[DBL2]    = "\001SHL BX,1\n";
  254.   code[DECbp]   = "\001DEC BYTE PTR [BX]\n";
  255.   code[DECwp]   = "\001DEC WORD PTR [BX]\n";
  256.   code[DIV12]   = "\011CWD\nIDIV BX\n";                 /* see gen() */
  257.   code[DIV12u]  = "\011XOR DX,DX\nDIV BX\n";            /* see gen() */
  258.   code[ENTER]   = "\100PUSH BP\nMOV BP,SP\n";
  259.   code[EQ10f]   = "\010OR AX,AX\nJE $+5\nJMP _<n>\n";
  260.   code[EQ12]    = "\211CALL __eq\n";
  261.   code[GE10f]   = "\010OR AX,AX\nJGE $+5\nJMP _<n>\n";
  262.   code[GE12]    = "\011CALL __ge\n";
  263.   code[GE12u]   = "\011CALL __uge\n";
  264.   code[GETb1m]  = "\020MOV AL,<m>\nCBW\n";
  265.   code[GETb1mu] = "\020MOV AL,<m>\nXOR AH,AH\n";
  266.   code[GETb1p]  = "\021MOV AL,?<n>??[BX]\nCBW\n";       /* see gen() */
  267.   code[GETb1pu] = "\021MOV AL,?<n>??[BX]\nXOR AH,AH\n"; /* see gen() */
  268.   code[GETb1s]  = "\020MOV AL,<n>[BP]\nCBW\n";
  269.   code[GETb1su] = "\020MOV AL,<n>[BP]\nXOR AH,AH\n";
  270.   code[GETw1m]  = "\020MOV AX,<m>\n";
  271.   code[GETw1m_] = "\020MOV AX,<m>";
  272.   code[GETw1n]  = "\020?MOV AX,<n>?XOR AX,AX?\n";
  273.   code[GETw1p]  = "\021MOV AX,?<n>??[BX]\n";            /* see gen() */
  274.   code[GETw1s]  = "\020MOV AX,<n>[BP]\n";
  275.   code[GETw2m]  = "\002MOV BX,<m>\n";
  276.   code[GETw2n]  = "\002?MOV BX,<n>?XOR BX,BX?\n";
  277.   code[GETw2p]  = "\021MOV BX,?<n>??[BX]\n";
  278.   code[GETw2s]  = "\002MOV BX,<n>[BP]\n";
  279.   code[GT10f]   = "\010OR AX,AX\nJG $+5\nJMP _<n>\n";
  280.   code[GT12]    = "\010CALL __gt\n";
  281.   code[GT12u]   = "\011CALL __ugt\n";
  282.   code[INCbp]   = "\001INC BYTE PTR [BX]\n";
  283.   code[INCwp]   = "\001INC WORD PTR [BX]\n";
  284.   code[WORD_]   = "\000 DW ";
  285.   code[WORDn]   = "\000 DW <n>\n";
  286.   code[WORDr0]  = "\000 DW <n> DUP(0)\n";
  287.   code[JMPm]    = "\000JMP _<n>\n";
  288.   code[LABm]    = "\000_<n>:\n";
  289.   code[LE10f]   = "\010OR AX,AX\nJLE $+5\nJMP _<n>\n";
  290.   code[LE12]    = "\011CALL __le\n";
  291.   code[LE12u]   = "\011CALL __ule\n";
  292.   code[LNEG1]   = "\010CALL __lneg\n";
  293.   code[LT10f]   = "\010OR AX,AX\nJL $+5\nJMP _<n>\n";
  294.   code[LT12]    = "\011CALL __lt\n";
  295.   code[LT12u]   = "\011CALL __ult\n";
  296.   code[MOD12]   = "\011CWD\nIDIV BX\nMOV AX,DX\n";      /* see gen() */
  297.   code[MOD12u]  = "\011XOR DX,DX\nDIV BX\nMOV AX,DX\n"; /* see gen() */
  298.   code[MOVE21]  = "\012MOV BX,AX\n";
  299.   code[MUL12]   = "\211IMUL BX\n";
  300.   code[MUL12u]  = "\211MUL BX\n";
  301.   code[NE10f]   = "\010OR AX,AX\nJNE $+5\nJMP _<n>\n";
  302.   code[NE12]    = "\211CALL __ne\n";
  303.   code[NEARm]   = "\000 DW _<n>\n";
  304.   code[OR12]    = "\211OR AX,BX\n";
  305.   code[PLUSn]   = "\000?+<n>??\n";
  306.   code[POINT1l] = "\020MOV AX,OFFSET _<l>+<n>\n";
  307.   code[POINT1m] = "\020MOV AX,OFFSET <m>\n";
  308.   code[POINT1s] = "\020LEA AX,<n>[BP]\n";
  309.   code[POINT2m] = "\002MOV BX,OFFSET <m>\n";
  310.   code[POINT2m_]= "\002MOV BX,OFFSET <m>";
  311.   code[POINT2s] = "\002LEA BX,<n>[BP]\n";
  312.   code[POP2]    = "\002POP BX\n";
  313.   code[PUSH1]   = "\110PUSH AX\n";
  314.   code[PUSH2]   = "\101PUSH BX\n";
  315.   code[PUSHm]   = "\100PUSH <m>\n";
  316.   code[PUSHp]   = "\100PUSH ?<n>??[BX]\n";
  317.   code[PUSHs]   = "\100PUSH ?<n>??[BP]\n";
  318.   code[PUT_m_]  = "\000MOV <m>";
  319.   code[PUTbm1]  = "\010MOV <m>,AL\n";
  320.   code[PUTbp1]  = "\011MOV [BX],AL\n";
  321.   code[PUTwm1]  = "\010MOV <m>,AX\n";
  322.   code[PUTwp1]  = "\011MOV [BX],AX\n";
  323.   code[rDEC1]   = "\010#DEC AX\n#";
  324.   code[rDEC2]   = "\010#DEC BX\n#";
  325.   code[REFm]    = "\000_<n>";
  326.   code[RETURN]  = "\000?MOV SP,BP\n??POP BP\nRET\n";
  327.   code[rINC1]   = "\010#INC AX\n#";
  328.   code[rINC2]   = "\010#INC BX\n#";
  329.   code[SUB_m_]  = "\000SUB <m>";
  330.   code[SUB12]   = "\011SUB AX,BX\n";                    /* see gen() */
  331.   code[SUB1n]   = "\010?SUB AX,<n>\n??";
  332.   code[SUBbpn]  = "\001SUB BYTE PTR [BX],<n>\n";
  333.   code[SUBwpn]  = "\001SUB WORD PTR [BX],<n>\n";
  334.   code[SWAP12]  = "\011XCHG AX,BX\n";
  335.   code[SWAP1s]  = "\012POP BX\nXCHG AX,BX\nPUSH BX\n";
  336.   code[SWITCH]  = "\012CALL __switch\n";
  337.   code[XOR12]   = "\211XOR AX,BX\n";
  338.   }
  339.  
  340. /***************** code generation functions *****************/
  341.  
  342. /*
  343. ** print all assembler info before any code is generated
  344. ** and ensure that the segments appear in the correct order.
  345. */
  346. header()  {
  347.   toseg(CODESEG);
  348.   outline("extrn __eq: near");
  349.   outline("extrn __ne: near");
  350.   outline("extrn __le: near");
  351.   outline("extrn __lt: near");
  352.   outline("extrn __ge: near");
  353.   outline("extrn __gt: near");
  354.   outline("extrn __ule: near");
  355.   outline("extrn __ult: near");
  356.   outline("extrn __uge: near");
  357.   outline("extrn __ugt: near");
  358.   outline("extrn __lneg: near");
  359.   outline("extrn __switch: near");
  360.   outline("dw 0"); /* force non-zero code pointers, word alignment */
  361.   toseg(DATASEG);
  362.   outline("dw 0"); /* force non-zero data pointers, word alignment */
  363.   }
  364.  
  365. /*
  366. ** print any assembler stuff needed at the end
  367. */
  368. trailer()  {  
  369.   char *cp;
  370.   cptr = STARTGLB;
  371.   while(cptr < ENDGLB) {
  372.     if(cptr[IDENT] == FUNCTION && cptr[CLASS] == AUTOEXT)
  373.       external(cptr + NAME, 0, FUNCTION);
  374.     cptr += SYMMAX;
  375.     }
  376.   if((cp = findglb("main")) && cp[CLASS]==STATIC)
  377.     external("_main", 0, FUNCTION);
  378.   toseg(NULL);
  379.   outline("END");
  380. #ifdef DISOPT
  381.     {
  382.     int i, *count;
  383.     printf(";opt   count\n");
  384.     for(i = -1; ++i <= HIGH_SEQ; ) {
  385.       count = seq[i];
  386.       printf("; %2u   %5u\n", i, *count);
  387.       poll(YES);
  388.       }
  389.     }  
  390. #endif 
  391.   }
  392.  
  393. /*
  394. ** remember where we are in the queue in case we have to back up.
  395. */
  396. setstage(before, start) int *before, *start; {
  397.   if((*before = snext) == 0)
  398.     snext = stage;
  399.   *start = snext;
  400.   }
  401.  
  402. /*
  403. ** generate code in staging buffer.
  404. */
  405. gen(pcode, value) int pcode, value; {
  406.   int newcsp;
  407.   switch(pcode) {
  408.     case GETb1pu:
  409.     case GETb1p:
  410.     case GETw1p: gen(MOVE21, 0); break;
  411.     case SUB12:
  412.     case MOD12:
  413.     case MOD12u:
  414.     case DIV12:
  415.     case DIV12u: gen(SWAP12, 0); break;
  416.     case PUSH1:  csp -= BPW;     break;
  417.     case POP2:   csp += BPW;     break;
  418.     case ADDSP:
  419.     case RETURN: newcsp = value; value -= csp; csp = newcsp;
  420.     }
  421.   if(snext == 0) {
  422.     outcode(pcode, value);
  423.     return;
  424.     }
  425.   if(snext >= slast) {
  426.     error("staging buffer overflow");
  427.     return;
  428.     }
  429.   snext[0] = pcode;
  430.   snext[1] = value;
  431.   snext += 2;
  432.   }
  433.  
  434. /*
  435. ** dump the contents of the queue.
  436. ** If start = 0, throw away contents.
  437. ** If before != 0, don't dump queue yet.
  438. */
  439. clearstage(before, start) int *before, *start; {
  440.   if(before) {
  441.     snext = before;
  442.     return;
  443.     }
  444.   if(start) dumpstage();
  445.   snext = 0;
  446.   }
  447.  
  448. /*
  449. ** dump the staging buffer
  450. */
  451. dumpstage() {
  452.   int i;
  453.   stail = snext;
  454.   snext = stage;
  455.   while(snext < stail) {
  456.     if(optimize) {
  457.       restart:
  458.       i = -1; 
  459.       while(++i <= HIGH_SEQ) if(peep(seq[i])) {
  460. #ifdef DISOPT
  461.         if(isatty(output))
  462.           fprintf(stderr, "                   optimized %2u\n", i);
  463. #endif
  464.         goto restart;
  465.         }
  466.       }
  467.     outcode(snext[0], snext[1]);
  468.     snext += 2;
  469.     }
  470.   }
  471.  
  472. /*
  473. ** change to a new segment
  474. ** may be called with NULL, CODESEG, or DATASEG
  475. */
  476. toseg(newseg) int newseg; {
  477.   if(oldseg == newseg)  return;
  478.   if(oldseg == CODESEG) outline("CODE ENDS");
  479.   else if(oldseg == DATASEG) outline("DATA ENDS");
  480.   if(newseg == CODESEG) {
  481.     outline("CODE SEGMENT PUBLIC");
  482.     outline("ASSUME CS:CODE, SS:DATA, DS:DATA");
  483.     }
  484.   else if(newseg == DATASEG) outline("DATA SEGMENT PUBLIC");
  485.   oldseg = newseg;
  486.   }
  487.  
  488. /*
  489. ** declare entry point
  490. */
  491. public(ident) int ident;{
  492.   if(ident == FUNCTION)
  493.        toseg(CODESEG);
  494.   else toseg(DATASEG);
  495.   outstr("PUBLIC ");
  496.   outname(ssname);
  497.   newline();
  498.   outname(ssname);
  499.   if(ident == FUNCTION) {
  500.     colon();
  501.     newline();
  502.     }
  503.   }
  504.  
  505. /*
  506. ** declare external reference
  507. */
  508. external(name, size, ident) char *name; int size, ident; {
  509.   if(ident == FUNCTION)
  510.        toseg(CODESEG);
  511.   else toseg(DATASEG);
  512.   outstr("EXTRN ");
  513.   outname(name);
  514.   colon();
  515.   outsize(size, ident);
  516.   newline();
  517.   }
  518.  
  519. /*
  520. ** output the size of the object pointed to.
  521. */
  522. outsize(size, ident) int size, ident; {
  523.   if(size == 1
  524.   && ident != POINTER
  525.   && ident != FUNCTION)      outstr("BYTE");
  526.   else if(ident != FUNCTION) outstr("WORD");
  527.   else                       outstr("NEAR");
  528.   }
  529.  
  530. /*
  531. ** point to following object(s)
  532. */
  533. point() {
  534.   outline(" DW $+2");
  535.   }
  536.  
  537. /*
  538. ** dump the literal pool
  539. */
  540. dumplits(size) int size; {
  541.   int j, k;
  542.   k = 0;
  543.   while (k < litptr) {
  544.     poll(1);                     /* allow program interruption */
  545.     if(size == 1)
  546.          gen(BYTE_, NULL);
  547.     else gen(WORD_, NULL);
  548.     j = 10;
  549.     while(j--) {
  550.       outdec(getint(litq + k, size));
  551.       k += size;
  552.       if(j == 0 || k >= litptr) {
  553.         newline();
  554.         break;
  555.         }
  556.       fputc(',', output);
  557.       }
  558.     }
  559.   }
  560.  
  561. /*
  562. ** dump zeroes for default initial values
  563. */
  564. dumpzero(size, count) int size, count; {
  565.   if(count > 0) {
  566.     if(size == 1)
  567.          gen(BYTEr0, count);
  568.     else gen(WORDr0, count);
  569.     }
  570.   }
  571.  
  572. /******************** optimizer functions ***********************/
  573.  
  574. /*
  575. ** Try to optimize sequence at snext in the staging buffer.
  576. */
  577. peep(seq) int *seq; {
  578.   int *next, *count, *pop, n, skip, tmp, reply;
  579.   char c;
  580.   next = snext;
  581.   count = seq++;
  582.   while(*seq) {
  583.     switch(*seq) {
  584.       case any:   if(next < stail)       break;      return (NO);
  585.       case pfree: if(isfree(PRI, next))  break;      return (NO);
  586.       case sfree: if(isfree(SEC, next))  break;      return (NO);
  587.       case comm:  if(*next & COMMUTES)   break;      return (NO);
  588.       case _pop:  if(pop = getpop(next)) break;      return (NO);
  589.       default:    if(next >= stail || *next != *seq) return (NO);
  590.       }
  591.     next += 2; ++seq;
  592.     }
  593.  
  594.   /****** have a match, now optimize it ******/
  595.  
  596.   *count += 1;
  597.   reply = skip = NO;
  598.   while(*(++seq) || skip) {
  599.     if(skip) {
  600.       if(*seq == 0) skip = NO;
  601.       continue;
  602.       }
  603.     if(*seq >= PCODES) {
  604.       c = *seq & 0xFF;            /* get low byte of command */
  605.       n = c;                      /* and sign extend into n */
  606.       switch(*seq & 0xFF00) {
  607.         case ife:   if(snext[1] != n) skip = YES;  break;
  608.         case ifl:   if(snext[1] >= n) skip = YES;  break;
  609.         case go:    snext += (n<<1);               break;
  610.         case gc:    snext[0] =  snext[(n<<1)];     goto done;
  611.         case gv:    snext[1] =  snext[(n<<1)+1];   goto done;
  612.         case sum:   snext[1] += snext[(n<<1)+1];   goto done;
  613.         case neg:   snext[1] = -snext[1];          goto done;
  614.         case topop: pop[0] = n; pop[1] = snext[1]; goto done;
  615.         case swv:   tmp = snext[1];
  616.                     snext[1] = snext[(n<<1)+1];
  617.                     snext[(n<<1)+1] = tmp;
  618.         done:       reply = YES;
  619.                     break;
  620.         }
  621.       }
  622.     else snext[0] = *seq;         /* set p-code */
  623.     }
  624.   return (reply);
  625.   }
  626.  
  627. /*
  628. ** Is the primary or secondary register free?
  629. ** Is it zapped or unused by the p-code at pp
  630. ** or a successor?  If the primary register is
  631. ** unused by it still may not be free if the
  632. ** context uses the value of the expression.
  633. */
  634. isfree(reg, pp) int reg, *pp; {
  635.   char *cp;
  636.   while(pp < stail) {
  637.     cp = code[*pp];
  638.     if(*cp & USES & reg) return (NO);
  639.     if(*cp & ZAPS & reg) return (YES);
  640.     pp += 2;
  641.     }
  642.   if(usexpr) return (reg & 001);   /* PRI => NO, SEC => YES at end */
  643.   else       return (YES);
  644.   }
  645.  
  646. /*
  647. ** Get place where the currently pushed value is popped?
  648. ** NOTE: Function arguments are not popped, they are
  649. ** wasted with an ADDSP.
  650. */
  651. getpop(next) int *next; {
  652.   char *cp;
  653.   int level;  level = 0;
  654.   while(YES) {
  655.     if(next >= stail)                     /* compiler error */
  656.       return 0;
  657.     if(*next == POP2)
  658.       if(level) --level;
  659.       else return next;                   /* have a matching POP2 */
  660.     else if(*next == ADDSP) {             /* after func call */
  661.       if((level -= (next[1]>>LBPW)) < 0)
  662.         return 0;
  663.       }
  664.     else {
  665.       cp = code[*next];                   /* code string ptr */
  666.       if(*cp & PUSHES) ++level;           /* must be a push */
  667.       } 
  668.     next += 2;
  669.     }
  670.   }
  671.  
  672. /******************* output functions *********************/
  673.  
  674. colon() {
  675.   fputc(':', output);
  676.   }
  677.  
  678. newline() {
  679.   fputc(NEWLINE, output);
  680.   }
  681.  
  682. /*
  683. ** output assembly code.
  684. */
  685. outcode(pcode, value) int pcode, value; {
  686.   int part, skip, count;
  687.   char *cp, *back;
  688.   part = back = 0;
  689.   skip = NO;
  690.   cp = code[pcode] + 1;          /* skip 1st byte of code string */
  691.   while(*cp) {
  692.     if(*cp == '<') {
  693.       ++cp;                      /* skip to action code */
  694.       if(skip == NO) switch(*cp) {
  695.         case 'm': outname(value+NAME); break; /* mem ref by label */
  696.         case 'n': outdec(value);       break; /* numeric constant */
  697.         case 'l': outdec(litlab);      break; /* current literal label */
  698.         }
  699.       cp += 2;                   /* skip past > */
  700.       }
  701.     else if(*cp == '?') {        /* ?..if value...?...if not value...? */
  702.       switch(++part) {
  703.         case 1: if(value == 0) skip = YES; break;
  704.         case 2: skip = !skip;              break;
  705.         case 3: part = 0; skip = NO;       break;
  706.         }
  707.       ++cp;                      /* skip past ? */
  708.       }
  709.     else if(*cp == '#') {        /* repeat #...# value times */
  710.       ++cp;
  711.       if(back == 0) {
  712.         if((count = value) < 1) {
  713.           while(*cp && *cp++ != '#') ;
  714.           continue;
  715.           }
  716.         back = cp;
  717.         continue;
  718.         }
  719.       if(--count > 0) cp = back;
  720.       else back = 0;
  721.       }
  722.     else if(skip == NO) fputc(*cp++, output);
  723.     else ++cp;
  724.     }
  725.   }
  726.  
  727. outdec(number)  int number; {
  728.   int k, zs;
  729.   char c, *q, *r;
  730.   zs = 0;
  731.   k = 10000;
  732.   if(number < 0) {
  733.     number = -number;
  734.     fputc('-', output);
  735.     }
  736.   while (k >= 1) {
  737.     q = 0;
  738.     r = number;
  739.     while(r >= k) {++q; r = r - k;}
  740.     c = q + '0';
  741.     if(c != '0' || k == 1 || zs) {
  742.       zs = 1;
  743.       fputc(c, output);
  744.       }
  745.     number = r;
  746.     k /= 10;
  747.     }
  748.   }
  749.  
  750. outline(ptr)  char ptr[];  {
  751.   outstr(ptr);
  752.   newline();
  753.   }
  754.  
  755. outname(ptr) char ptr[]; {
  756.   outstr("_");
  757.   while(*ptr >= ' ') fputc(*ptr++, output);
  758.   }
  759.  
  760. outstr(ptr) char ptr[]; {
  761.   poll(1);           /* allow program interruption */
  762.   while(*ptr >= ' ') fputc(*ptr++, output);
  763.   }
  764.  
  765.